/**
 * @file liste.h
 * @brief Librairie de liste doublement chainée.
 * @author Florian.B Rachid.D
 * @version 1.0
 * @date 4 avril 2012
 *
 * Librairie fournissant un gestionnaire de liste chainée.
 *
 */

#ifndef __LIST_H__
#define __LIST_H__


#include <stdio.h>
#include <stdlib.h>

typedef void * Element;

/**
 * @enum ListReturn
 * @brief Constantes d'erreurs.
 *
 * ListReturn est une série de constantes prédéfinies pour diverses futures
 * fonctions de l'objet List.
 */
typedef enum
  {
    LIST_SUCCESS, /*!< Succès. */
    LIST_EMPTY, /*!< Liste vide. */
    LIST_NOT_EMPTY, /*!< Liste non vide. */
    LIST_CUR_NULL, /*!< Le courrant de la liste est égale à NULL. */
    LIST_CUR_FIRST, /*!< Le courrant de la liste est égale au premier élément
     de la liste. */
    LIST_CUR_LAST, /*!< Le courrant est égale au dernier élément de la liste. */
    LIST_CUR_NOT_LAST, /*!< Le courrant n'est pas égale au dernier. */
    LIST_NOT_FOUND, /*!< L'élément recherché n'a pas été trouvé. */
    LIST_ERR, /*!< Erreur. */
    LIST_COMP_DIF, /*!< Retour de la fonction de comparaison différence. */
    LIST_COMP_EQ, /*!< Retour de la fonction de comparaison égaux. */
    LIST_NB_RET /*!< Nombre total de constantes de retour. */
  }ListReturn;

/**
 * @struct Cell
 * @brief Objet Cellule.
 *
 * Cell est un petit objet qui permet de sauvegarder un élément dans
 * la liste. Il connaît le suivant.
 */
typedef struct _Cell
{
  Element element; /*!< Élément de la cellule. */
  struct _Cell *next; /*!< Cellule suivante ou NULL si Cell est la dernière
   Cellule. */
  struct _Cell *previous; /*!< Cellule précédente ou NULL si Cell est la
   première Cellule. */
} Cell;

/**
 * @struct List
 * @brief Objet Liste.
 *
 * List est la liste chainée. Elle contient le premier élément, l'élément
 * courant ainsi que le dernier. Le nombre d'élément contenu dans la liste
 * est aussi connu. Les divers pointeurs de fonction permettent de gérer 
 * en mémoire les éléments de la liste.
 */
typedef struct _List
{
  Cell *adFirst; /*!< Permière cellule */
  Cell *adLast; /*!< Dernière cellule */
  Cell *adCurrent; /*!< Cellule courante */
  int nbElement; /*!< Nombre d'élément dans la liste */
  /**<
   * @fn void (*create) (Element *dest, const Element src)
   * @brief Fonction de création par recopie d'élément
   *
   * @param[in,out] dest Élément qui sera dans la liste
   * @param src Élément qui sera copié dans dest.
   */
  void (*create)(Element *dest, const Element src);
  /**< 
   * @fn void (*destroy)(Element *element)
   * @brief Fonction de suppréssion d'un élément
   *
   * @param[in,out] element L'élément à supprimer, il devra être à NULL.
   */
  void (*destroy)(Element *element);
  /**<
   * @fn void (*print)(const Element)
   * @brief Fonction d'affichage d'un élément.
   *
   * @param element Élément à afficher.
   */
  void (*print)(const Element element);
  /**<
   * @fn int (*compare)(const Element elementA, const Element elementB)
   * @brief Fonction de comparaison de deux élément.
   *
   * @param elementA Premier élément.
   * @param elementB Deuxième élément.
   * @return LIST_COMP_EQ si l'elementA et l'elementB sont égaux,
   * LIST_COMP_LOW si l'elementA est inférieur à l'elementB et
   * LIST_COMP_TOP sinon.
   */
  ListReturn (*compare)(const Element elementA, const Element elementB);
} List;

/**
 * @fn void initializes_List(List *list,
 void (*create)(Element *dest, const Element src),
 void (*destroy)(Element *element),
 int (*compare)(const Element elementA, const Element elementB),
 void (*print)(const Element element)
 )
 * @brief Fonction d'initialisation d'une liste chainée.
 *
 * @param list Liste à initialiser.
 * @param create Pointeur de fonction pour la création d'élément.
 * @param destroy Pointeur de fonction pour la destruction d'un élément.
 * @param compare Pointeur de fonction de comparaison.
 * @param print Pointeur de fonction pour l'affichage d'un élément.
 */
void initialize_List(List *list,
		     void (*create)(Element *dest, const Element src),
             void (*destroy)(Element *element),
             ListReturn (*compare)(const Element elementA,
                                   const Element elementB),
		     void (*print)(const Element element)
		     );

/**
 * @fn ListReturn initializeCopy_List(List *l1, const List *l2)
 * @brief Fonction d'initialisation d'une liste listA par recopie de 
 * la liste listB. Les deux listes sont totalement indépendantes.
 *
 * @param[in,out] listA Liste qui sera initialisée et qui correspond à une
 * copie de listB.
 * @param listB Liste de copie.
 * @return LIST_SUCCESS si aucune erreur n'est détecter et LIST_ERR en cas
 * d'erreur. 
 */
ListReturn initializeCopy_List(List *listA, const List *listB);

/**
 * @fn void testament_List(List *l)
 * @brief Fonction de libération d'un liste.
 *
 * @param[in,out] list Liste qui sera libérée.
 */
void testament_List(List *list);

/**
 * @fn ListReturn assignment_List(List *listA, const List *listB)
 * @brief Fonction de copie de la liste listB dans la liste listB. 
 * Les deux listes sont totalement indépendantes.
 * 
 * @param[in,out] listA La liste de destination.
 * @param listB La liste source.
 * @return LIST_ERR en cas d'erreur de copie et LIST_SUCCESS pour un 
 * succès
 */
ListReturn assignment_List(List *listA, const List *listB);

/**
 * @fn ListReturn isEmpty_List(const List *list)
 * @brief Fonction pour tester une liste vide ou non.
 *
 * @param list La liste à tester.
 * @return LIST_EMPTY si la liste est vide et LIST_NOT_EMPTY sinon.
 */
ListReturn isEmpty_List(const List *l);

/**
 * @fn ListReturn destroyFirst_List(List *list)
 * @brief Fonction de suppression du premier élément de la liste.
 *
 * @param[in,out] list La liste qui perdra son premier élément.
 * @return LIST_EMPTY si la liste est vide et LIST_SUCCESS sinon.
 */
ListReturn destroyFirst_List(List *list);

/**
 * @fn ListReturn destroyCurrent_List(List *list)
 * @brief Fonction de suppression de l'élément courrant de la liste.
 *
 * @param[in,out] list La liste qui perdra son élément courrant.
 * @return LIST_EMPTY si la liste est vide, LIST_CUR_NULL si le courrant 
 * est égale à NULL et LIST_SUCCESS sinon.
 */
ListReturn destroyCurrent_List(List *list);

/**
 * @fn ListReturn destroyLast_List(List *list)
 * @brief Fonction de suppression du dernier élément de la liste.
 *
 * @param[in,out] list La liste qui perdra son dernier élément.
 * @return LIST_ERR en cas d'erreur, LIST_EMPTY si la liste est vide et 
 * LIST_SUCCESS sinon.
 */
ListReturn destroyLast_List(List *list);

/**
 * @fn ListReturn clear_List(List *list)
 * @brief Fonction qui vide la liste.
 *
 * @param[in,out] list La liste qui perdra tout ses élément.
 * @return LIST_ERR en cas d'erreur et LIST_SUCCESS sinon.
 */
ListReturn clear_List(List *l);

/**
 * @fn ListReturn insertLast_List(const Element element, List *list)
 * @brief Fonction qui ajoute un élément à la fin de la liste.
 *
 * @param element L'élément à insérer.
 * @param[in,out] list La liste qui prendra l'élément.
 * @return LIST_ERR en cas d'erreur et LIST_SUCCESS sinon.
 */
ListReturn insertLast_List(List *list, Element const element);

/**
 * @fn ListReturn insertCurrent_List(const Element element, List *list)
 * @brief Fonction qui ajoute un élément avant l'élément courrant de la liste.
 *
 * @param element L'élément à insérer.
 * @param[in,out] list La liste qui prendra l'élément.
 * @return LIST_ERR en cas d'erreur et LIST_SUCCESS sinon.
 */
ListReturn insertCurrent_List(List *list, const Element element);

/**
 * @fn ListReturn insertFirst_List(const Element element, List *list)
 * @brief Fonction qui ajoute un élément au début de la liste.
 *
 * @param element L'élément à insérer.
 * @param[in,out] list La liste qui prendra l'élément.
 * @return LIST_ERR en cas d'erreur et LIST_SUCCESS sinon.
 */
ListReturn insertFirst_List(List *list, const Element element);

/**
 * @fn int print_List(const List *list)
 * @brief Fonction qui affiche la liste en grâce à la fonction print.
 * Si la fonction print est NULL, la fonction retourne LIST_ERR.
 *
 * @param list La liste qui sera afficher.
 * @return LIST_ERR si la fonction print est NULL et LIST_SUCCESS sinon.
 */
int print_List(const List *l);

/**
 * @fn ListReturn findElement_List(const Element element, List *list)
 * @brief Fonction qui recherche l'élément element grâce à la fonction 
 * compare.
 *
 * @param element L'élément recherché.
 * @param[in,out] list La liste où on recherche l'élément.
 * @return LIST_ERR si la fonction compare est NULL, LIST_NOT_FOUND si 
 * l'élément n'a pas été trouvé et LIST_SUCCESS sinon.
 */
ListReturn findElement_List(List *list, const Element element);

/**
 * @fn Element getDataCurrent_List(const List *list)
 * @brief Fonction qui retourne l'élément du courrant de la liste ou NULL.
 *
 * @param list La liste dont on veut l'élément.
 * @return L'élément du courrant ou NULL si le courrant ne pointe pas sur
 * une cellule valide.
 */
Element getDataCurrent_List(const List *list);

/**
 * @fn Element getDataFirst_List(const List *list)
 * @brief Fonction qui retourne le premier élément ou NULL si aucun.
 * 
 * @param list La liste dont on veut l'élément.
 * @return Le premier élément ou NULL si aucun élément est présent 
 * dans la list.
 */
Element getDataFirst_List(const List *list);

/**
 * @fn Element getDataLast_List(const List *list)
 * @brief Fonction qui retourne le dernier élément ou NULL si aucun.
 * 
 * @param list La liste dont on veut l'élément.
 * @return Le dernier élément ou NULL si aucun élément est présent 
 * dans la list.
 */
Element getDataLast_List(const List *list);

/**
 * @fn void first_List(List *list)
 * @brief Fonction qui place le courrant sur le premier élément de la 
 * liste.
 *
 * @param[in,out] list La liste de travail.
 */
void first_List(List *list);

/**
 * @fn ListReturn next_List(List *list)
 * @brief Fonction qui déplace le courrant vers le suivant.
 * 
 * @param[in,out] list La liste de travail.
 * @return LIST_CUR_NULL quand le courrant est à NULL (il vient de passer
 * le dernier élément de la liste). LIST_SUCCESS quand le courrant est 
 * passé sur l'élément suivant de la liste et LIST_CUR_FIRST lorsque le 
 * courrant est revenu sur le premier élément de la liste (le courrant 
 * doit être égale à NULL avant de pouvoir retourner sur le premier 
 * élément de la liste).
 */
ListReturn next_List(List *list);

/**
 * @fn ListReturn isLast_List(const List *list)
 * @brief Fonction qui test si l'élément courrant est sur le dernier 
 * élément de la liste.
 *
 * @param list La liste de travail.
 * @return LIST_CUR_LAST si le courrant est sur le dernier élément de la 
 * liste et LIST_CUR_NOT_LAST sinon.
 */
ListReturn isLast_List(const List *list);

/**
 * @fn ListReturn destroyAt_List(List *list, const int index)
 * @brief Fonction de suppression de l'élément à la position index dans 
 * la liste.
 *
 * @param[in,out] list La liste qui perdra l'élément.
 * @param index L'index dans la liste entre 0 et le nombre d'élément dans
 * la liste moins 1.
 * @return LIST_SUCCESS si l'élément à bien été supprimé ou LIST_ERR en 
 * cas d'erreur (si l'index est inférieur à 0 ou suppérieur ou égale au 
 * nombre d'élément dans la liste) ou LIST_EMPTY si la liste est vide.
 */
ListReturn destroyAt_List(List *list, const int indice);

/**
 * @fn ListReturn insertAt_List(const Element element, List *list,
 * const int index)
 * @brief Fonction qui ajoute un élément à la position index dans la 
 * liste.
 *
 * @param element L'élément à insérer.
 * @param[in,out] list La liste qui prendra l'élément.
 * @param index L'index dans la liste entre 0 et le nombre d'élément de la
 * liste.
 * @return LIST_SUCCESS si l'élément à bien été inséré ou LIST_ERR en 
 * cas d'erreur (si l'index est inférieur à 0 ou suppérieur ou égale au 
 * nombre d'élément dans la liste).
 */
ListReturn insertAt_List(List *list, const int index, const Element element);

/**
 * @fn Element getDataAt_List(List *list, const int index)
 * @brief Fonction qui retourne le élément à la position index ou NULL 
 * si aucun élément.
 * 
 * @param list La liste dont on veut l'élément.
 * @param index L'index dans la liste entre 0 et le nombre d'élément dans
 * la liste moins 1.
 * @return L'élément à la position index ou NULL si l'index est inférieur
 * à 0 ou suppérieur ou égale au nombre d'élément dans la liste.
 */
Element getDataAt_List(List *list, const int index);

/**
 * @fn int getSize_List(const List *list)
 * @brief Fonction qui retourne la taille de la liste.
 *
 * @param list La liste de travail.
 * @return La taille de la liste.
 */
int getSize_List(const List *list);

#endif
